﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PServiceBus.Core.Interface;
using Phoenix.ReflectionExtensions;
using PServiceBus.Core.Runtime.Extensions;
using System.Text.RegularExpressions;
using PServiceBus.Core.Runtime.Serializers;
using PServiceBus.Serializer.Xml;
using System.Collections;

namespace PServiceBus.Core.Runtime.Transformations {
    public class CsvTransformation : ITransformation {
        #region IDataTransformation Members

        public string Transform(Dictionary<string, object> param) {
            return String.Join(",", param.Values) + "\r\n";
        }

        public string Transform(List<Dictionary<string, object>> list) {
            var sb = new StringBuilder();
            if (list.Count > 0) sb.AppendFormat("{0}\r\n",String.Join(",", list[0].Keys));
            foreach (var param in list) sb.Append(Transform(param));
            return sb.ToString();
        }

        public IEnumerable<TData> Transform<TData>(string data) where TData : class {
            var sData = Regex.Split(data, "\r\n");
            var list = new List<TData>();
            var hasData = sData.Length > 1;
            var header = hasData ? sData[0].Split(',') : null;
            var headerLength = header != null ? header.Length : 0;
            var dataType = ReflectionHelper.GenerateInterface<TData>();
            for (var i = 1; i < sData.Length && hasData; i++ ) {
                var sDataText = sData[i];
                if (String.IsNullOrWhiteSpace(sDataText)) continue;
                var tokens = sDataText.Split(',');
                var obj = ReflectionHelper.New<TData>();
                for (var j = 0; j < headerLength; j++) {
                    var prop = dataType.GetPropertyEx(header[j]);
                    if (prop == null) continue;
                    var value = tokens[j];
                    var isXmlBase64 = value.IsXmlBase64();
                    value = isXmlBase64 ? String.Format("<Data>{0}</Data>", value.XmlBase64ToXml()) : value;
                    prop.SetValueEx(obj,
                        isXmlBase64 ? XmlSerializer.Deserialize(value, prop.PropertyType) : this.ChangeType(value, prop.PropertyType));
                }
                list.Add(obj);
            }
            return list;
        }

        public Type GetCanonicalType(string data) {
            var xml = new StringBuilder();
            xml.Append("<List><Items type=\"Items\">");
            var sData = Regex.Split(data, "\r\n");
            var hasData = sData.Length > 1;
            var header = hasData ? sData[0].Split(',') : null;
            var headerLength = header != null ? header.Length : 0;
            for (var i = 1; i < sData.Length && hasData; i++) {
                var sDataText = sData[i];
                if (String.IsNullOrWhiteSpace(sDataText)) continue;
                var tokens = sDataText.Split(',');
                xml.Append("<Message>");
                for (var j = 0; j < headerLength; j++) {
                    var key = header[j];
                    var value = tokens[j];
                    var isXmlBase64 = value.IsXmlBase64();
                    xml.AppendFormat("<{0}>{1}</{0}>", key, isXmlBase64 ? value.XmlBase64ToXml() : value);
                }
                xml.Append("</Message>");
                break;//Breaking because we only need to get first object to construct canonical data model
            }
            xml.Append("</Items></List>");
            return this.ToCanonicalType((JsonSerializer.XmlToJson(xml.ToString()).FromJson() as IList)[0] as Dictionary<string, object>);
        }
        #endregion
    }
}
